package com.example.gaoyang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.gaoyang.constant.Constant;
import com.example.gaoyang.domain.*;
import com.example.gaoyang.domain.request.SysUserRequest;
import com.example.gaoyang.domain.vo.SysElementVO;
import com.example.gaoyang.domain.vo.SysUserVO;
import com.example.gaoyang.enums.ResultEnum;
import com.example.gaoyang.exception.InvalidParameterException;
import com.example.gaoyang.mapper.SysUserMapper;
import com.example.gaoyang.request.Result;
import com.example.gaoyang.service.*;
import com.example.gaoyang.threadlocal.UserThreadLocal;
import com.example.gaoyang.util.ResultUtil;
import com.example.gaoyang.util.TokenUtil;
import com.example.gaoyang.wrapper.SysUserWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Resource
    private SysRoleElementService sysRoleElementService;

    @Resource
    private SysElementService sysElementService;

    @Resource
    private SysRoleService sysRoleService;

    @Override
    public void addUser(SysUserRequest sysUserRequest) {
        // 获取用户名
        String username = sysUserRequest.getUsername();
        // 获取密码
        String password = sysUserRequest.getPassword();
        // 用户名和密码不能为空
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            throw new InvalidParameterException("用户名或密码不能为空");
        }
        // 根据用户名获取系统用户表数据，保证唯一性
        SysUser sysUser = this.getOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUsername, username)
        );
        if (sysUser != null) {
            throw new InvalidParameterException(String.format("用户名[%s]已存在,无法注册", username));
        }
        SysUser sysUserAdd = BeanUtil.copyProperties(sysUserRequest, SysUser.class);
        Long userId = IdUtil.getSnowflake().nextId();
        sysUserAdd.setId(userId);
        sysUserAdd.setStatus(Constant.INTEGER_ONE);
        sysUserAdd.setCreateTime(new Date());
        this.save(sysUserAdd);
    }

    @Override
    public void removeUser(SysUserRequest sysUserRequest) {
        // id不能为空
        Long id = sysUserRequest.getId();
        if (id == null) {
            throw new InvalidParameterException("参数id缺失");
        }
        this.removeById(id);
    }

    @Override
    public SysUserVO login(SysUserRequest sysUserRequest) {
        // 用户名
        String username = sysUserRequest.getUsername();
        // 判断用户名密码否为空
        if (StringUtils.isEmpty(username)) {
            throw new InvalidParameterException("用户名不能为空");
        }
        // 判断用户名是否存在
        SysUser sysUser = this.getOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUsername, username)
        );
        if (sysUser == null) {
            throw new InvalidParameterException(String.format("用户名[%s]不存在,请先注册", username));
        }
        // 密码(此密码已经加密)
        String password = sysUserRequest.getPassword();
        // 判断密码是否正确
        if (!StringUtils.equals(sysUser.getPassword(), password)) {
            throw new InvalidParameterException("用户名或密码错误,请重试");
        }
        // 设置token相关
        this.setUserToken(sysUser);
        // 设置threadLocal
        UserThreadLocal.set(sysUser);
        SysUserVO sysUserVO = BeanUtil.copyProperties(sysUser, SysUserVO.class);
        sysUserVO.setIdStr(String.valueOf(sysUser.getId()));
        // 用户id
        Long userId = sysUser.getId();
        return sysUserVO;
    }

    @Override
    public void logout(SysUserRequest sysUserRequest) {
        // 获取当前用户
        Long id = sysUserRequest.getId();
        SysUser sysUser = this.getOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getId, id)
        );
        UserThreadLocal.remove();
        sysUser.setToken(Constant.STRING_NULL);
        sysUser.setTokenTime(null);
        this.updateById(sysUser);
    }

    @Override
    public SysUserVO getUserInfo(SysUserRequest sysUserRequest) {
        SysUser sysUser = this.getById(sysUserRequest.getId());
        // 获取所有权限
        List<SysRole> sysRoleList = sysRoleService.list();
        // 构建权限id-权限名称的map
        Map<Long, String> roleMap = sysRoleList.stream()
                .collect(Collectors.toMap(SysRole::getId, SysRole::getRoleName));
        SysUserVO sysUserVO = BeanUtil.copyProperties(sysUser, SysUserVO.class);
        sysUserVO.setRoleName(roleMap.get(sysUser.getRoleId()));
        return sysUserVO;
    }

    @Override
    public List<SysUserVO> getUserList(SysUserRequest sysUserRequest) {
        LambdaQueryWrapper<SysUser> wrapper = this.createWrapper(sysUserRequest);
        List<SysUserVO> list = BeanUtil.copyToList(this.list(wrapper), SysUserVO.class);
        // 获取所有权限
        List<SysRole> sysRoleList = sysRoleService.list();
        // 构建权限id-权限名称的map
        Map<Long, String> roleMap = sysRoleList.stream()
                .collect(Collectors.toMap(SysRole::getId, SysRole::getRoleName));
        // 赋值角色名称
        list.forEach(item -> item.setRoleName(roleMap.get(item.getRoleId())));
        return list;
    }

    @Override
    public IPage<SysUserVO> getUserPage(IPage<SysUser> page, SysUserRequest sysUserRequest) {
        page.setCurrent(sysUserRequest.getPageNum());
        page.setSize(sysUserRequest.getPageSize());
        // 请注意:SQL server在分页查询时，需要先排序
        IPage<SysUserVO> userVOIPage = new SysUserWrapper().pageVO(this.page(page, this.createWrapper(sysUserRequest)));
        // 获取所有权限
        List<SysRole> sysRoleList = sysRoleService.list();
        // 构建权限id-权限名称的map
        Map<Long, String> roleMap = sysRoleList.stream()
                .collect(Collectors.toMap(SysRole::getId, SysRole::getRoleName));
        userVOIPage.getRecords().forEach(item -> {
            // 赋值角色名称
            item.setRoleName(roleMap.get(item.getRoleId()));
        });
        return userVOIPage;
    }

    @Override
    public void updateUser(SysUserRequest sysUserRequest) {
        // id不能缺失
        Long id = sysUserRequest.getId();
        if (id == null) {
            throw new InvalidParameterException("参数id缺失");
        }
        // 用户名不能重复(前端已经disabled，此处无需判断)
        SysUser sysUser = BeanUtil.copyProperties(sysUserRequest, SysUser.class);
        sysUser.setUpdateTime(new Date());
        this.updateById(sysUser);
    }


    @Override
    public List<SysElementVO> getSysElementByUser(SysUserRequest sysUserRequest) {
        // 获取用户角色
        Long roleId = sysUserRequest.getRoleId();
        // 角色不能为空
        if (roleId == null) {
            throw new InvalidParameterException("参数roleId缺失");
        }
        // 根据角色获取该角色的所有权限元素
        List<Long> elementIds = sysRoleElementService.list(new LambdaQueryWrapper<SysRoleElement>()
                .eq(SysRoleElement::getRoleId, roleId)
        ).stream().map(SysRoleElement::getElementId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(elementIds)) {
            return new ArrayList<>();
        }
        // 根据元素id查询实体
        List<SysElement> sysElements = sysElementService.listByIds(elementIds);
        List<SysElementVO> sysElementVOList = BeanUtil.copyToList(sysElements, SysElementVO.class);
        return sysElementService.buildElementTree(sysElementVOList);
    }

    @Override
    public List<SysElementVO> getButtonByUser(SysUserRequest sysUserRequest) {
        // 获取用户角色
        Long roleId = sysUserRequest.getRoleId();
        // 角色不能为空
        if (roleId == null) {
            throw new InvalidParameterException("参数roleId缺失");
        }
        // 根据角色获取该角色的所有按钮
        List<Long> elementIds = sysRoleElementService.list(new LambdaQueryWrapper<SysRoleElement>()
                .eq(SysRoleElement::getRoleId, roleId)
        ).stream().map(SysRoleElement::getElementId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(elementIds)) {
            return new ArrayList<>();
        }
        // 根据元素id查询按钮
        List<SysElement> sysElements = sysElementService.listByIds(elementIds)
                .stream().filter(item -> item.getElementType().equals(Constant.INTEGER_TWO))
                .collect(Collectors.toList());
        List<SysElementVO> sysElementVOList = BeanUtil.copyToList(sysElements, SysElementVO.class);
        return sysElementVOList;
    }

    @Override
    public void resetPassword(SysUserRequest sysUserRequest) {
        // 当前用户名
        String username = sysUserRequest.getUsername();
        if (StringUtils.isEmpty(username)) {
            throw new InvalidParameterException("参数username缺失");
        }
        // 根据用户名获取密码
        SysUser sysUser = this.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
        String password = sysUser == null ? null : sysUser.getPassword();
        // 旧密码
        String oldPassword = sysUserRequest.getOldPassword();
        // 旧密码确保输入正确
        if (!StringUtils.equals(oldPassword, password)) {
            throw new InvalidParameterException("原密码错误");
        }
        // 新密码
        String newPassword = sysUserRequest.getNewPassword();
        // 新密码确认
        String newPasswordConfirm = sysUserRequest.getNewPasswordConfirm();
        if (StringUtils.isEmpty(newPassword) || !newPassword.equals(newPasswordConfirm)) {
            throw new InvalidParameterException("两次密码不一致");
        }
        if (sysUser != null) {
            sysUser.setPassword(newPassword);
            // 更新时间
            sysUser.setUpdateTime(new Date());
            this.updateById(sysUser);
        }
    }

    /**
     * 设置用户token并返回
     * @param sysUser
     */
    private void setUserToken(SysUser sysUser) {
        // 为用户创建token
        sysUser.setToken(TokenUtil.buildToken(sysUser));
        // 设置token有效时间位当前时间加一天
        Date validTime = new Date(new Date().getTime() + 60 * 60 * 24 * 1000);
        sysUser.setTokenTime(validTime);
        this.updateById(sysUser);
    }

    private LambdaQueryWrapper<SysUser> createWrapper(SysUserRequest sysUserRequest) {
        return new LambdaQueryWrapper<SysUser>()
                .like(!StringUtils.isEmpty(sysUserRequest.getUsername()), SysUser::getUsername, sysUserRequest.getUsername())
                .like(!StringUtils.isEmpty(sysUserRequest.getNickname()), SysUser::getNickname, sysUserRequest.getNickname())
                .like(!StringUtils.isEmpty(sysUserRequest.getPassword()), SysUser::getPassword, sysUserRequest.getPassword())
                .eq(ObjectUtil.isNotEmpty(sysUserRequest.getStatus()), SysUser::getStatus, sysUserRequest.getStatus())
                .eq(!StringUtils.isEmpty(sysUserRequest.getToken()), SysUser::getToken, sysUserRequest.getToken())
                .eq(ObjectUtil.isNotEmpty(sysUserRequest.getRoleId()), SysUser::getRoleId, sysUserRequest.getRoleId())
                .orderByDesc(SysUser::getUsername);
    }
}
